// Copyright (c) Microsoft Corporation.  All rights reserved.
#pragma once

#include <msxml2.h>

/*
Object model of Simple Content Format XML

CScfElement
    CScfContentBase
        CScfContentElement      <content>
        CScfDialogElement       <dialog>
        CScfMenuElement         <menu>
    CScfSimpleElementBase
        CScfBtnElement          <btn>
        CScfTxtElement          <txt>
        CScfItemElement         <item>
    CScfImgElement              <img>
    CScfBrElement               <br>
    CScfDivElement              <div>
*/

enum SCF_ELEMENT_TYPE {
    SCF_UNKNOWN_ELEMENT,
    SCF_BODY_ELEMENT,
    SCF_BR_ELEMENT,
    SCF_BTN_ELEMENT,
    SCF_CLR_ELEMENT,
    SCF_CONTENT_ELEMENT,
    SCF_DIALOG_ELEMENT,
    SCF_DIV_ELEMENT,
    SCF_EM_ELEMENT,
    SCF_IMG_ELEMENT,
    SCF_ITEM_ELEMENT,
    SCF_MENU_ELEMENT,
    SCF_TXT_ELEMENT
};

enum SCF_BTNKEY
{
    SCF_BTNKEY_UNKNOWN,
    SCF_BTNKEY_ENTER,
    SCF_BTNKEY_BACK,
    SCF_BTNKEY_HOME,
    SCF_BTNKEY_LEFT,
    SCF_BTNKEY_RIGHT
};

enum SCF_ALIGN
{
    SCF_ALIGN_LEFT,
    SCF_ALIGN_CENTER,
    SCF_ALIGN_RIGHT,
};

enum SCF_BGFIT
{
    SCF_BGFIT_SCALE,
    SCF_BGFIT_TILE,
    SCF_BGFIT_CENTER
};

enum SCF_IMAGEFIT
{
    SCF_IMAGEFIT_NATIVE,
    SCF_IMAGEFIT_WIDTH,
    SCF_IMAGEFIT_SCREEN,
    SCF_IMAGEFIT_AUTO
};

enum SCF_SELECTACTION
{
    SCF_SELECTACTION_UNKNOWN,
    SCF_SELECTACTION_TARGET,
    SCF_SELECTACTION_MENUID
};

#define SCF_FLAG_RGB_ATTR       1
#define SCF_FLAG_MENUID_ATTR    2

class CScfElement
{
public:
    CScfElement()
    {
        m_ElemType = SCF_UNKNOWN_ELEMENT;
        m_Flags = 0;
    }
    
    virtual ~CScfElement()
    {
    }

    SCF_ELEMENT_TYPE GetElementType() { return m_ElemType; }
    BOOL HasRgbAttr()    { return (m_Flags & SCF_FLAG_RGB_ATTR)    != 0; }
    BOOL HasMenuIdAttr() { return (m_Flags & SCF_FLAG_MENUID_ATTR) != 0; }
    
protected:
    SCF_ELEMENT_TYPE m_ElemType;
    ULONG m_Flags;
};

// base class for btn, txt, item
class CScfSimpleElementBase : public CScfElement
{
public:
    HRESULT SetText(LPCWSTR pwszText)
    {
        HRESULT hr = S_OK;
        
        try
        {
            m_text = pwszText;
        }
        catch(...)
        {
            hr = E_FAIL;
        }
        
        return hr;
    }
    
    HRESULT AppendText(LPCWSTR pwchText, UINT cchText)
    {
        HRESULT hr = S_OK;
        
        try
        {
            m_text.append(pwchText, cchText);
        }
        catch(...)
        {
            hr = E_FAIL;
        }
        
        return hr;
    }

    UINT GetTextLength() const
    {
        return (UINT)m_text.size();
    }

    LPCWSTR GetText()
    {
        return m_text.c_str();
    }

private:
    wstring m_text;
};

class CScfBtnElement : public CScfSimpleElementBase
{
public:
    CScfBtnElement()
    {
        m_ElemType = SCF_BTN_ELEMENT;
        m_btnKey = (SCF_BUTTON_IDS)0;
        m_targetId = 0;
    }

    HRESULT Initialize(ISAXAttributes *pAttributes);

    SCF_BUTTON_IDS m_btnKey;
    CONTENT_ID m_targetId;
};

// common base for content, menu, dialog
class CScfContentBase : public CScfElement
{
public:
    ~CScfContentBase()
    {
        for(size_t i = 0; i < m_elems.size(); i++)
        {
            delete m_elems[i];
        }

        for(size_t i = 0; i < m_btns.size(); i++)
        {
            delete m_btns[i];
        }
    }

    HRESULT Initialize(ISAXAttributes *pAttributes);

    HRESULT AddChild(CScfElement *pChildElem)
    {
        HRESULT hr = S_OK;
        
        try
        {
            m_elems.push_back(pChildElem);
        }
        catch(...)
        {
            hr = E_FAIL;
        }
        
        return hr;
    }

    HRESULT AddButton(CScfBtnElement *pBtnElement)
    {
        HRESULT hr = S_OK;
        
        try
        {
            m_btns.push_back(pBtnElement);
        }
        catch(...)
        {
            hr = E_FAIL;
        }
        
        return hr;
    }
    
    HRESULT SetTitle(LPCWSTR pwszTitle)
    {
        HRESULT hr = S_OK;
        
        try
        {
            m_title = pwszTitle;
        }
        catch(...)
        {
            hr = E_FAIL;
        }
        
        return hr;
    }
    
    size_t GetChildCount() { return m_elems.size(); }
    CScfElement *GetChild(size_t i) { return m_elems[i]; }

    size_t GetButtonCount() { return m_btns.size(); }
    CScfBtnElement *GetButton(size_t i) { return m_btns[i]; }
    
    LPCWSTR GetTitle() { return m_title.c_str(); }
    
    virtual BOOL HasImageReferenceOf(CONTENT_ID imgid);
    
    UINT m_id;

protected:
    wstring m_title;
    
private:
    vector<CScfElement *> m_elems;      // content: txt or img or br
                                        // menu   : item
                                        // dialog : txt
    vector<CScfBtnElement *> m_btns;
};

class CScfContentElement : public CScfContentBase
{
public:
    CScfContentElement()
    {
        m_ElemType = SCF_CONTENT_ELEMENT;
        m_bg = 0;
        m_bgfit = SCF_BGFIT_SCALE;
        m_menuId = 0;
    }
    
    ~CScfContentElement()
    {
    }

    HRESULT Initialize(ISAXAttributes *pAttributes);

    virtual BOOL HasImageReferenceOf(CONTENT_ID imgid);

    CONTENT_ID m_bg;
    SCF_BGFIT  m_bgfit;
    CONTENT_ID m_menuId;
};

class CScfDialogElement : public CScfContentBase
{
public:
    CScfDialogElement()
    {
        m_ElemType = SCF_DIALOG_ELEMENT;
        m_imgId = 0;
    }

    HRESULT Initialize(ISAXAttributes *pAttributes);

    virtual BOOL HasImageReferenceOf(CONTENT_ID imgid);

    CONTENT_ID m_imgId;
};

struct CScfTxtEmRange
{
    UINT        m_from;
    UINT        m_to;
};

struct CScfTxtClrRange
{
    UINT        m_from;
    UINT        m_to;
    COLORREF    m_rgb;
};

class CScfTxtElement : public CScfSimpleElementBase
{
public:
    CScfTxtElement()
    {
        m_ElemType = SCF_TXT_ELEMENT;
        m_align = SCF_ALIGN_LEFT;
        m_wrap = TRUE;
        m_rgb = 0;
    }

    HRESULT Initialize(ISAXAttributes *pAttributes);
    
    HRESULT AddEmRange(int from, int to)
    {
        HRESULT hr = S_OK;
        CScfTxtEmRange range;
        
        range.m_from = from;
        range.m_to = to;
        
        try
        {
            m_EmRanges.push_back(range);
        }
        catch(...)
        {
            hr = E_FAIL;
        }
        
        return hr;
    }

    HRESULT AddClrRange(int from, int to, COLORREF rgb)
    {
        HRESULT hr = S_OK;
        CScfTxtClrRange range;
        
        range.m_from = from;
        range.m_to = to;
        range.m_rgb = rgb;
        
        try
        {
            m_ClrRanges.push_back(range);
        }
        catch(...)
        {
            hr = E_FAIL;
        }
        
        return hr;
    }
    
    VOID SetRgbAttr(COLORREF rgb)
    {
        m_rgb = rgb;
        m_Flags |= SCF_FLAG_RGB_ATTR;
    }
    
    COLORREF GetRgbAttr()
    {
        return m_rgb;
    }
    
    SCF_ALIGN m_align;
    BOOL m_wrap;

    list<CScfTxtClrRange> m_ClrRanges;
    list<CScfTxtEmRange> m_EmRanges;

private:
    COLORREF m_rgb;
};

class CScfImgElement : public CScfElement
{
public:
    CScfImgElement()
    {
        m_ElemType = SCF_IMG_ELEMENT;
        m_id = 0;
        m_align = SCF_ALIGN_LEFT;
        m_fit = SCF_IMAGEFIT_AUTO;
    }

    HRESULT Initialize(ISAXAttributes *pAttributes);

    UINT m_id;
    SCF_ALIGN m_align;
    SCF_IMAGEFIT m_fit;
};

class CScfItemElement : public CScfSimpleElementBase
{
public:
    CScfItemElement()
    {
        m_ElemType = SCF_ITEM_ELEMENT;
        m_id = 0;
        m_targetId = 0;
        m_imgId = 0;
        m_def = FALSE;
        m_enable = TRUE;
        m_menuId = 0;
    }

    HRESULT Initialize(ISAXAttributes *pAttributes);

    UINT m_id;
    CONTENT_ID m_targetId;
    CONTENT_ID m_imgId;
    BOOL m_def;
    BOOL m_enable;
    UINT m_menuId;
};

class CScfMenuElement : public CScfContentBase
{
public:
    CScfMenuElement()
    {
        m_ElemType = SCF_MENU_ELEMENT;
        m_selectaction = SCF_SELECTACTION_UNKNOWN;
    }

    HRESULT Initialize(ISAXAttributes *pAttributes);

    SCF_SELECTACTION m_selectaction;
};

class CScfBrElement : public CScfElement
{
public:
    CScfBrElement()
    {
        m_ElemType = SCF_BR_ELEMENT;
    }

    HRESULT Initialize(ISAXAttributes* pAttributes) { UNREFERENCED_PARAMETER(pAttributes); return S_OK; }
};

class CScfDivElement : public CScfElement
{
public:
    CScfDivElement()
    {
        m_ElemType = SCF_DIV_ELEMENT;
    }

    HRESULT Initialize(ISAXAttributes* pAttributes) { UNREFERENCED_PARAMETER(pAttributes); return S_OK; }
};
